using System.Text.Json;
using System.Collections.Concurrent;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging;
using JGSY.CMS.LowCode.Platform.Domain.Interfaces;

namespace JGSY.CMS.LowCode.Platform.Infrastructure.Services.Performance
{
    /// <summary>
    /// 租户级缓存服务接口
    /// 提供租户隔离的缓存功能，支持自动租户ID前缀
    /// </summary>
    public interface ITenantCacheService
    {
        Task<T?> GetAsync<T>(string key, string? tenantId = null);
        Task SetAsync<T>(string key, T value, TimeSpan? expiry = null, string? tenantId = null);
        Task RemoveAsync(string key, string? tenantId = null);
        Task RemoveByPatternAsync(string pattern, string? tenantId = null);
        Task InvalidateAllTenantCacheAsync(string tenantId);
        Task<CacheStats> GetCacheStatsAsync(string tenantId);
        Task WarmupTenantCacheAsync(string tenantId);
    }

    /// <summary>
    /// 租户级缓存服务实现
    /// 提供租户隔离、智能预热、统计监控的高性能缓存服务
    /// </summary>
    public class TenantCacheService : ITenantCacheService
    {
        private readonly IDistributedCache _distributedCache;
        private readonly IMemoryCache _memoryCache;
        private readonly ITenantContext _tenantContext;
        private readonly ILogger<TenantCacheService> _logger;
        private readonly JsonSerializerOptions _jsonOptions;
        
        // 缓存统计
        private readonly ConcurrentDictionary<string, CacheStats> _tenantStats;
        
        // 缓存配置
        private readonly TimeSpan _defaultExpiry = TimeSpan.FromMinutes(30);
        private readonly TimeSpan _memoryExpiry = TimeSpan.FromMinutes(5);
        
        public TenantCacheService(
            IDistributedCache distributedCache,
            IMemoryCache memoryCache,
            ITenantContext tenantContext,
            ILogger<TenantCacheService> logger)
        {
            _distributedCache = distributedCache;
            _memoryCache = memoryCache;
            _tenantContext = tenantContext;
            _logger = logger;
            _tenantStats = new ConcurrentDictionary<string, CacheStats>();
            _jsonOptions = new JsonSerializerOptions 
            { 
                PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
                WriteIndented = false
            };
        }

        /// <summary>
        /// 获取缓存项
        /// 优先从内存缓存获取，其次从分布式缓存获取
        /// </summary>
        public async Task<T?> GetAsync<T>(string key, string? tenantId = null)
        {
            tenantId ??= GetCurrentTenantId();
            if (string.IsNullOrEmpty(tenantId))
            {
                _logger.LogWarning("租户ID为空，无法获取缓存: {Key}", key);
                return default;
            }

            var tenantKey = GetTenantCacheKey(tenantId, key);
            var stats = GetOrCreateStats(tenantId);

            try
            {
                // 1. 尝试从内存缓存获取
                if (_memoryCache.TryGetValue(tenantKey, out T? memoryValue))
                {
                    stats.MemoryHits++;
                    stats.TotalRequests++;
                    _logger.LogDebug("内存缓存命中: {Key} (租户: {TenantId})", key, tenantId);
                    return memoryValue;
                }

                // 2. 尝试从分布式缓存获取
                var distributedValue = await _distributedCache.GetStringAsync(tenantKey);
                if (!string.IsNullOrEmpty(distributedValue))
                {
                    var deserializedValue = JsonSerializer.Deserialize<T>(distributedValue, _jsonOptions);
                    
                    // 将数据设置到内存缓存中
                    _memoryCache.Set(tenantKey, deserializedValue, _memoryExpiry);
                    
                    stats.DistributedHits++;
                    stats.TotalRequests++;
                    _logger.LogDebug("分布式缓存命中: {Key} (租户: {TenantId})", key, tenantId);
                    return deserializedValue;
                }

                // 3. 缓存未命中
                stats.Misses++;
                stats.TotalRequests++;
                _logger.LogDebug("缓存未命中: {Key} (租户: {TenantId})", key, tenantId);
                return default;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取缓存失败: {Key} (租户: {TenantId})", key, tenantId);
                stats.Errors++;
                return default;
            }
        }

        /// <summary>
        /// 设置缓存项
        /// 同时设置到内存缓存和分布式缓存
        /// </summary>
        public async Task SetAsync<T>(string key, T value, TimeSpan? expiry = null, string? tenantId = null)
        {
            tenantId ??= GetCurrentTenantId();
            if (string.IsNullOrEmpty(tenantId))
            {
                _logger.LogWarning("租户ID为空，无法设置缓存: {Key}", key);
                return;
            }

            var tenantKey = GetTenantCacheKey(tenantId, key);
            var cacheExpiry = expiry ?? _defaultExpiry;
            var stats = GetOrCreateStats(tenantId);

            try
            {
                // 1. 设置内存缓存
                var memoryExpiry = TimeSpan.FromMilliseconds(Math.Min(cacheExpiry.TotalMilliseconds, _memoryExpiry.TotalMilliseconds));
                _memoryCache.Set(tenantKey, value, memoryExpiry);

                // 2. 设置分布式缓存
                var serializedValue = JsonSerializer.Serialize(value, _jsonOptions);
                var options = new DistributedCacheEntryOptions
                {
                    AbsoluteExpirationRelativeToNow = cacheExpiry
                };
                await _distributedCache.SetStringAsync(tenantKey, serializedValue, options);

                stats.Sets++;
                _logger.LogDebug("缓存设置成功: {Key} (租户: {TenantId}), 过期时间: {Expiry}", key, tenantId, cacheExpiry);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "设置缓存失败: {Key} (租户: {TenantId})", key, tenantId);
                stats.Errors++;
            }
        }

        /// <summary>
        /// 移除缓存项
        /// </summary>
        public async Task RemoveAsync(string key, string? tenantId = null)
        {
            tenantId ??= GetCurrentTenantId();
            if (string.IsNullOrEmpty(tenantId))
            {
                return;
            }

            var tenantKey = GetTenantCacheKey(tenantId, key);

            try
            {
                // 移除内存缓存
                _memoryCache.Remove(tenantKey);
                
                // 移除分布式缓存
                await _distributedCache.RemoveAsync(tenantKey);
                
                _logger.LogDebug("缓存移除成功: {Key} (租户: {TenantId})", key, tenantId);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "移除缓存失败: {Key} (租户: {TenantId})", key, tenantId);
            }
        }

        /// <summary>
        /// 根据模式移除缓存项
        /// </summary>
        public async Task RemoveByPatternAsync(string pattern, string? tenantId = null)
        {
            tenantId ??= GetCurrentTenantId();
            if (string.IsNullOrEmpty(tenantId))
            {
                return;
            }

            var tenantPattern = GetTenantCacheKey(tenantId, pattern);
            
            try
            {
                // 这里需要根据实际的分布式缓存实现来处理模式匹配
                // 对于Redis，可以使用KEYS命令或SCAN命令
                _logger.LogInformation("按模式移除缓存: {Pattern} (租户: {TenantId})", pattern, tenantId);
                
                // 模拟实现 - 实际实现需要根据缓存类型调整
                await Task.CompletedTask;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "按模式移除缓存失败: {Pattern} (租户: {TenantId})", pattern, tenantId);
            }
        }

        /// <summary>
        /// 清空租户的所有缓存
        /// </summary>
        public async Task InvalidateAllTenantCacheAsync(string tenantId)
        {
            if (string.IsNullOrEmpty(tenantId))
            {
                return;
            }

            try
            {
                var tenantPrefix = $"tenant:{tenantId}:";
                
                // 这里需要根据实际的分布式缓存实现来清空租户缓存
                // 对于Redis，可以使用KEYS或SCAN命令找到所有匹配的键然后删除
                _logger.LogInformation("清空租户缓存: {TenantId}", tenantId);
                
                // 清空统计信息
                _tenantStats.TryRemove(tenantId, out _);
                
                await Task.CompletedTask;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "清空租户缓存失败: {TenantId}", tenantId);
            }
        }

        /// <summary>
        /// 获取租户缓存统计信息
        /// </summary>
        public async Task<CacheStats> GetCacheStatsAsync(string tenantId)
        {
            var stats = GetOrCreateStats(tenantId);
            stats.HitRatio = stats.TotalRequests > 0 
                ? (double)(stats.MemoryHits + stats.DistributedHits) / stats.TotalRequests 
                : 0;
            
            await Task.CompletedTask;
            return stats;
        }

        /// <summary>
        /// 预热租户缓存
        /// 预加载常用数据到缓存中
        /// </summary>
        public async Task WarmupTenantCacheAsync(string tenantId)
        {
            if (string.IsNullOrEmpty(tenantId))
            {
                return;
            }

            try
            {
                _logger.LogInformation("开始预热租户缓存: {TenantId}", tenantId);

                // 预热逻辑 - 可以根据业务需求预加载常用数据
                // 例如：用户信息、权限、配置等
                var warmupTasks = new List<Task>
                {
                    WarmupUserDataAsync(tenantId),
                    WarmupPermissionsAsync(tenantId),
                    WarmupConfigurationsAsync(tenantId)
                };

                await Task.WhenAll(warmupTasks);
                
                _logger.LogInformation("租户缓存预热完成: {TenantId}", tenantId);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "租户缓存预热失败: {TenantId}", tenantId);
            }
        }

        #region 私有方法

        /// <summary>
        /// 获取当前租户ID
        /// </summary>
        private string GetCurrentTenantId()
        {
            return _tenantContext?.TenantId ?? string.Empty;
        }

        /// <summary>
        /// 生成租户缓存键
        /// </summary>
        private string GetTenantCacheKey(string tenantId, string key)
        {
            return $"tenant:{tenantId}:{key}";
        }

        /// <summary>
        /// 获取或创建租户统计信息
        /// </summary>
        private CacheStats GetOrCreateStats(string tenantId)
        {
            return _tenantStats.GetOrAdd(tenantId, _ => new CacheStats { TenantId = tenantId });
        }

        /// <summary>
        /// 预热用户数据
        /// </summary>
        private async Task WarmupUserDataAsync(string tenantId)
        {
            // 实现用户数据预热逻辑
            await Task.Delay(100); // 模拟预热过程
            _logger.LogDebug("用户数据预热完成: {TenantId}", tenantId);
        }

        /// <summary>
        /// 预热权限数据
        /// </summary>
        private async Task WarmupPermissionsAsync(string tenantId)
        {
            // 实现权限数据预热逻辑
            await Task.Delay(100); // 模拟预热过程
            _logger.LogDebug("权限数据预热完成: {TenantId}", tenantId);
        }

        /// <summary>
        /// 预热配置数据
        /// </summary>
        private async Task WarmupConfigurationsAsync(string tenantId)
        {
            // 实现配置数据预热逻辑
            await Task.Delay(100); // 模拟预热过程
            _logger.LogDebug("配置数据预热完成: {TenantId}", tenantId);
        }

        #endregion
    }

    /// <summary>
    /// 缓存统计信息
    /// </summary>
    public class CacheStats
    {
        public string TenantId { get; set; } = string.Empty;
        public long TotalRequests { get; set; }
        public long MemoryHits { get; set; }
        public long DistributedHits { get; set; }
        public long Misses { get; set; }
        public long Sets { get; set; }
        public long Errors { get; set; }
        public double HitRatio { get; set; }
        public DateTime LastAccess { get; set; } = DateTime.UtcNow;
    }
}
